<!DOCTYPE html>



  


<html class="theme-next gemini use-motion" lang="zh-Hans">
<head><meta name="generator" content="Hexo 3.8.0">
  <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css">







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css">

<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="java,">










<meta name="description" content="logback详解引用自: https://segmentfault.com/a/1190000008315137#articleHeader28概览简单地说，Logback 是一个 Java 领域的日志框架。它被认为是 Log4J 的继承人。Logback 主要由三个模块组成：    logback-core logback-classic logback-access  logback-cor">
<meta name="keywords" content="java">
<meta property="og:type" content="article">
<meta property="og:title" content="logback详解">
<meta property="og:url" content="https://blog.xiezc.xyz/2018/10/31/java日志框架/logback详解/index.html">
<meta property="og:site_name" content="xiezc的小站">
<meta property="og:description" content="logback详解引用自: https://segmentfault.com/a/1190000008315137#articleHeader28概览简单地说，Logback 是一个 Java 领域的日志框架。它被认为是 Log4J 的继承人。Logback 主要由三个模块组成：    logback-core logback-classic logback-access  logback-cor">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="https://blog.xiezc.xyz/2018/10/31/java日志框架/logback详解/_v_images/_1540968598_15153.png">
<meta property="og:image" content="https://blog.xiezc.xyz/2018/10/31/java日志框架/logback详解/_v_images/_1540969013_11481.png">
<meta property="og:updated_time" content="2019-04-04T14:26:54.278Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="logback详解">
<meta name="twitter:description" content="logback详解引用自: https://segmentfault.com/a/1190000008315137#articleHeader28概览简单地说，Logback 是一个 Java 领域的日志框架。它被认为是 Log4J 的继承人。Logback 主要由三个模块组成：    logback-core logback-classic logback-access  logback-cor">
<meta name="twitter:image" content="https://blog.xiezc.xyz/2018/10/31/java日志框架/logback详解/_v_images/_1540968598_15153.png">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Gemini',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="https://blog.xiezc.xyz/2018/10/31/java日志框架/logback详解/">





  <title>logback详解 | xiezc的小站</title>
  





  <script type="text/javascript">
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?8ae02d8cf311eabbae2621ff2d51a260";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>




</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">xiezc的小站</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle">xiezc的小站</p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br>
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br>
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br>
            
            归档
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://blog.xiezc.xyz/2018/10/31/java日志框架/logback详解/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="xiezc">
      <meta itemprop="description" content>
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="xiezc的小站">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">logback详解</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-31T14:38:35+08:00">
                2018-10-31
              </time>
            

            

            
          </span>

          
            <span class="post-category">
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/java/" itemprop="url" rel="index">
                    <span itemprop="name">java</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          
             <span id="/2018/10/31/java日志框架/logback详解/" class="leancloud_visitors" data-flag-title="logback详解">
               <span class="post-meta-divider">|</span>
               <span class="post-meta-item-icon">
                 <i class="fa fa-eye"></i>
               </span>
               
                 <span class="post-meta-item-text">阅读次数&#58;</span>
               
                 <span class="leancloud-visitors-count"></span>
             </span>
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <h1 id="logback详解"><a href="#logback详解" class="headerlink" title="logback详解"></a>logback详解</h1><h2 id="引用自-https-segmentfault-com-a-1190000008315137-articleHeader28"><a href="#引用自-https-segmentfault-com-a-1190000008315137-articleHeader28" class="headerlink" title="引用自: https://segmentfault.com/a/1190000008315137#articleHeader28"></a>引用自: <a href="https://segmentfault.com/a/1190000008315137#articleHeader28" target="_blank" rel="noopener">https://segmentfault.com/a/1190000008315137#articleHeader28</a></h2><h2 id="概览"><a href="#概览" class="headerlink" title="概览"></a>概览</h2><p>简单地说，Logback 是一个 Java 领域的日志框架。它被认为是 Log4J 的继承人。<br>Logback 主要由三个模块组成：  </p>
<ul>
<li>logback-core</li>
<li>logback-classic</li>
<li>logback-access</li>
</ul>
<p>logback-core 是其它模块的基础设施，其它模块基于它构建，显然，logback-core 提供了一些关键的通用机制。logback-classic 的地位和作用等同于 Log4J，它也被认为是 Log4J 的一个改进版，并且它实现了简单日志门面 SLF4J；而 logback-access 主要作为一个与 Servlet 容器交互的模块，比如说 tomcat 或者 jetty，提供一些与 HTTP 访问相关的功能。</p>
<p>目前 Logback 的使用很广泛，很多知名的开源软件都使用了 Logback作为日志框架，比如说 Akka，Apache Camel 等。</p>
<h2 id="Logback-与-Log4J"><a href="#Logback-与-Log4J" class="headerlink" title="Logback 与 Log4J"></a>Logback 与 Log4J</h2><p>实际上，这两个日志框架都出自同一个开发者之手，Logback 相对于 Log4J 有更多的优点</p>
<ul>
<li><p>同样的代码路径，Logback 执行更快</p>
</li>
<li><p>更充分的测试</p>
</li>
<li><p>原生实现了 SLF4J API（Log4J 还需要有一个中间转换层）</p>
</li>
<li><p>内容更丰富的文档</p>
</li>
<li><p>支持 XML 或者 Groovy 方式配置</p>
</li>
<li><p>配置文件自动热加载</p>
</li>
<li><p>从 IO 错误中优雅恢复</p>
</li>
<li><p>自动删除日志归档</p>
</li>
<li><p>自动压缩日志成为归档文件</p>
</li>
<li><p>支持 Prudent 模式，使多个 JVM 进程能记录同一个日志文件</p>
</li>
<li><p>支持配置文件中加入条件判断来适应不同的环境</p>
</li>
<li><p>更强大的过滤器</p>
</li>
<li><p>支持 SiftingAppender（可筛选 Appender）</p>
</li>
<li><p>异常栈信息带有包信息</p>
</li>
</ul>
<h2 id="快速上手"><a href="#快速上手" class="headerlink" title="快速上手"></a>快速上手</h2><p>想在 Java 程序中使用 Logback，需要依赖三个 jar 包，分别是 slf4j-api，logback-core，logback-classic。其中 slf4j-api 并不是 Logback 的一部分，是另外一个项目，但是强烈建议将 slf4j 与 Logback 结合使用。要引用这些 jar 包，在 maven 项目中引入以下3个 dependencies<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.slf4j<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>slf4j-api<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.7.5<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>ch.qos.logback<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>logback-core<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0.11<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>ch.qos.logback<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>logback-classic<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0.11<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h3 id="第一个简单的例子"><a href="#第一个简单的例子" class="headerlink" title="第一个简单的例子"></a>第一个简单的例子</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> io.beansoft.logback.demo.universal;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.slf4j.Logger;</span><br><span class="line"><span class="keyword">import</span> org.slf4j.LoggerFactory;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> beanlam</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2017年2月9日 下午11:17:53</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SimpleDemo</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Logger logger = LoggerFactory.getLogger(SimpleDemo.class);</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        logger.info(<span class="string">"Hello, this is a line of log message logged by Logback"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>以上代码的运行结果是：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">23:19:41.131 [main] INFO i.b.l.demo.universal.SimpleDemo - Hello, this is a line of log message logged by Logback</span><br></pre></td></tr></table></figure></p>
<p>注意到这里，代码里并没有引用任何一个跟 Logback 相关的类，而是引用了 SLF4J 相关的类，这边是使用 SLF4J 的好处，在需要将日志框架切换为其它日志框架时，无需改动已有的代码。</p>
<p><code>LoggerFactory</code>的 <code>getLogger()</code>方法接收一个参数，以这个参数决定 logger 的名字，这里传入了 <code>SimpleDemo</code>这个类的 Class 实例，那么 <code>logger</code>的名字便是 <code>SimpleDemo</code>这个类的全限定类名：<code>io.beansoft.logback.demo.universal.SimpleDemo</code></p>
<h3 id="让-Logback-打印出一些它自身的内部消息"><a href="#让-Logback-打印出一些它自身的内部消息" class="headerlink" title="让 Logback 打印出一些它自身的内部消息"></a>让 Logback 打印出一些它自身的内部消息</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> io.beansoft.logback.demo.universal;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.slf4j.Logger;</span><br><span class="line"><span class="keyword">import</span> org.slf4j.LoggerFactory;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> ch.qos.logback.classic.LoggerContext;</span><br><span class="line"><span class="keyword">import</span> ch.qos.logback.core.util.StatusPrinter;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> beanlam</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2017年2月9日 下午11:31:55</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LogInternalStateDemo</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Logger logger = LoggerFactory.getLogger(LogInternalStateDemo.class);</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        logger.info(<span class="string">"Hello world"</span>);</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//打印 Logback 内部状态</span></span><br><span class="line">        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();</span><br><span class="line">        StatusPrinter.print(lc);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>除了打印正常的日志信息，还打印出了 Logback 自身的内部状态信息<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">23:33:19.340 [main] INFO  i.b.l.d.u.LogInternalStateDemo - Hello world</span><br><span class="line">23:33:19,265 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]</span><br><span class="line">23:33:19,265 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]</span><br><span class="line">23:33:19,265 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.xml]</span><br><span class="line">23:33:19,266 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Setting up default configuration.</span><br></pre></td></tr></table></figure></p>
<h2 id="Logger，Appenders-与-Layouts"><a href="#Logger，Appenders-与-Layouts" class="headerlink" title="Logger，Appenders 与 Layouts"></a>Logger，Appenders 与 Layouts</h2><p>在 logback 里，最重要的三个类分别是</p>
<ul>
<li><p>Logger</p>
</li>
<li><p>Appender</p>
</li>
<li><p>Layout</p>
</li>
</ul>
<p>Logger 类位于 logback-classic 模块中， 而 Appender 和 Layout 位于 logback-core 中，这意味着， Appender 和 Layout 并不关心 Logger 的存在，不依赖于 Logger，同时也能看出， Logger 会依赖于 Appender 和 Layout 的协助，日志信息才能被正常打印出来。</p>
<h3 id="分层命名规则"><a href="#分层命名规则" class="headerlink" title="分层命名规则"></a>分层命名规则</h3><p>为了可以控制哪些信息需要输出，哪些信息不需要输出，logback 中引进了一个 分层 概念。每个 logger 都有一个 name，这个 name 的格式与 Java 语言中的包名格式相同。这也是前面的例子中直接把一个 class 对象传进 LoggerFactory.getLogger() 方法作为参数的原因。</p>
<p>logger 的 name 格式决定了多个 logger 能够组成一个树状的结构，为了维护这个分层的树状结构，每个 logger 都被绑定到一个 logger 上下文中，这个上下文负责厘清各个 logger 之间的关系。</p>
<p>例如， 命名为 <code>io.beansoft</code> 的 logger，是命名为 <code>io.beansoft.logback</code>的 logger 的父亲，是命名为<code>io.beansoft.logback.demo</code> 的 logger 的祖先。</p>
<p>在 logger 上下文中，有一个 root logger，作为所有 logger 的祖先，这是 logback 内部维护的一个 logger，并非开发者自定义的 logger。</p>
<p>可通过以下方式获得这个 logger :<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);</span><br></pre></td></tr></table></figure></p>
<p>同样，通过 logger 的 name，就能获得对应的其它 logger 实例。</p>
<p>Logger 这个接口主要定义的方法有：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.slf4j; </span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Logger</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Printing methods: </span></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">trace</span><span class="params">(String message)</span></span>;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">debug</span><span class="params">(String message)</span></span>;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">info</span><span class="params">(String message)</span></span>; </span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">warn</span><span class="params">(String message)</span></span>; </span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">error</span><span class="params">(String message)</span></span>; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h3 id="日志打印级别"><a href="#日志打印级别" class="headerlink" title="日志打印级别"></a>日志打印级别</h3><p>logger 有日志打印级别，可以为一个 logger 指定它的日志打印级别。<br>如果不为一个 logger 指定打印级别，那么它将继承离他最近的一个有指定打印级别的祖先的打印级别。这里有一个容易混淆想不清楚的地方，如果 logger 先找它的父亲，而它的父亲没有指定打印级别，那么它会立即忽略它的父亲，往上继续寻找它爷爷，直到它找到 root logger。因此，也能看出来，要使用 logback， 必须为 root logger 指定日志打印级别。</p>
<p>日志打印级别从低级到高级排序的顺序是：<br><code>TRACE &lt; DEBUG &lt; INFO &lt; WARN &lt; ERROR</code><br>如果一个 logger 允许打印一条具有某个日志级别的信息，那么它也必须允许打印具有比这个日志级别更高级别的信息，而不允许打印具有比这个日志级别更低级别的信息。</p>
<p>举个例子：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> io.beansoft.logback.demo.universal;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.slf4j.Logger;</span><br><span class="line"><span class="keyword">import</span> org.slf4j.LoggerFactory;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> ch.qos.logback.classic.Level;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> beanlam</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2017年2月10日 上午12:20:33</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LogLevelDemo</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//这里强制类型转换时为了能设置 logger 的 Level</span></span><br><span class="line">        ch.qos.logback.classic.Logger logger = </span><br><span class="line">                (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(<span class="string">"com.foo"</span>);</span><br><span class="line">        logger.setLevel(Level.INFO);</span><br><span class="line">        </span><br><span class="line">        Logger barlogger = LoggerFactory.getLogger(<span class="string">"com.foo.Bar"</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 这个语句能打印，因为 WARN &gt; INFO</span></span><br><span class="line">        logger.warn(<span class="string">"can be printed because WARN &gt; INFO"</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 这个语句不能打印，因为 DEBUG &lt; INFO. </span></span><br><span class="line">        logger.debug(<span class="string">"can not be printed because DEBUG &lt; INFO"</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// barlogger 是 logger 的一个子 logger</span></span><br><span class="line">        <span class="comment">// 它继承了 logger 的级别 INFO</span></span><br><span class="line">        <span class="comment">// 以下语句能打印，因为 INFO &gt;= INFO</span></span><br><span class="line">        barlogger.info(<span class="string">"can be printed because INFO &gt;= INFO"</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 以下语句不能打印，因为 DEBUG &lt; INFO</span></span><br><span class="line">        barlogger.debug(<span class="string">"can not be printed because DEBUG &lt; INFO"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>打印结果是：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">00:27:19.251 [main] WARN  com.foo - can be printed because WARN &gt; INFO</span><br><span class="line">00:27:19.255 [main] INFO  com.foo.Bar - can be printed because INFO &gt;= INFO</span><br></pre></td></tr></table></figure></p>
<h3 id="获取-logger"><a href="#获取-logger" class="headerlink" title="获取 logger"></a>获取 logger</h3><p>在 logback 中，每个 logger 都是一个单例，调用 LoggerFactory.getLogger 方法时，如果传入的 logger name 相同，获取到的 logger 都是同一个实例。</p>
<p>在为 logger 命名时，用类的全限定类名作为 logger name 是最好的策略，这样能够追踪到每一条日志消息的来源。</p>
<h3 id="Appender-和-Layout"><a href="#Appender-和-Layout" class="headerlink" title="Appender 和 Layout"></a>Appender 和 Layout</h3><p>在 logback 的世界中，日志信息不仅仅可以打印至 console，也可以打印至文件，甚至输出到网络流中，日志打印的目的地由 Appender 来决定，不同的 Appender 能将日志信息打印到不同的目的地去。</p>
<p>Appender 是绑定在 logger 上的，同时，一个 logger 可以绑定多个 Appender，意味着一条信息可以同时打印到不同的目的地去。例如，常见的做法是，日志信息既输出到控制台，同时也记录到日志文件中，这就需要为 logger 绑定两个不同的 logger。</p>
<p>Appender 是绑定在 logger 上的，而 logger 又有继承关系，因此一个 logger 打印信息时的目的地 Appender 需要参考它的父亲和祖先。在 logback 中，默认情况下，如果一个 logger 打印一条信息，那么这条信息首先会打印至它自己的 Appender，然后打印至它的父亲和父亲以上的祖先的 Appender，但如果它的父亲设置了 <code>additivity = false</code>，那么这个 logger 除了打印至它自己的 Appender 外，只会打印至其父亲的 Appender，因为它的父亲的 additivity 属性置为了 false，开始变得忘祖忘宗了，所以这个 logger 只认它父亲的 Appender；此外，对于这个 logger 的父亲来说，如果父亲的 logger 打印一条信息，那么它只会打印至自己的 Appender中（如果有的话），因为父亲已经忘记了爷爷及爷爷以上的那些父辈了。</p>
<p>打印的日志除了有打印的目的地外，还有日志信息的展示格式。在 logback 中，用 Layout 来代表日志打印格式。比如说，PatternLayout 能够识别以下这条格式：<br><code>%-4relative [%thread] %-5level %logger{32} - %msg%n</code><br>然后打印出来的格式效果是：<br><code>176 [main] DEBUG manual.architecture.HelloWorld2 - Hello world.</code></p>
<p>上面这个格式的第一个字段代表从程序启动开始后经过的毫秒数，第二个字段代表打印出这条日志的线程名字，第三个字段代表日志信息的日志打印级别，第四个字段代表 logger name，第五个字段是日志信息，第六个字段仅仅是代表一个换行符。</p>
<h3 id="参数化打印日志"><a href="#参数化打印日志" class="headerlink" title="参数化打印日志"></a>参数化打印日志</h3><p>经常能看到打印日志的时候，使用以下这种方式打印日志：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">logger.debug(<span class="string">"the message is "</span> + msg + <span class="string">" from "</span> + somebody);</span><br></pre></td></tr></table></figure></p>
<p>这种打印日志的方式有个缺点，就是无论日志级别是什么，程序总要先执行<code>&quot;the message is &quot; + msg + &quot; from &quot; + somebody</code> 这段字符串的拼接操作。当 logger 设置的日志级别为比 DEBUG 级别更高级别时，DEBUG 级别的信息不回被打印出来的，显然，字符串拼接的操作是不必要的，当要拼接的字符串很大时，这无疑会带来很大的性能白白损耗。</p>
<p>于是，一种改进的打印日志方式被人们发现了：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span>(logger.isDebugEnabled()) &#123; </span><br><span class="line">  logger.debug(<span class="string">"the message is "</span> + msg + <span class="string">" from "</span> + somebody);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>这样的方式确实能避免字符串拼接的不必要损耗，但这也不是最好的方法，当日志级别为 DEBUG 时，那么打印这行消息，需要判断两次日志级别。一次是logger.isDebugEnabled()，另一次是 logger.debug() 方法内部也会做的判断。这样也会带来一点点效率问题，如果能找到更好的方法，谁愿意无视白白消耗的效率。</p>
<p>有一种更好的方法，那就是提供占位符的方式，以参数化的方式打印日志，例如上述的语句，可以是这样的写法：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">logger.debug(<span class="string">"the message &#123;&#125; is from &#123;&#125;"</span>, msg, somebody);</span><br></pre></td></tr></table></figure></p>
<p>这样的方式，避免了字符串拼接，也避免了多一次日志级别的判断。</p>
<h3 id="logback-内部运行流程"><a href="#logback-内部运行流程" class="headerlink" title="logback 内部运行流程"></a>logback 内部运行流程</h3><p><img src="_v_images/_1540968598_15153.png" alt></p>
<p>当应用程序发起一个记录日志的请求，例如 info() 时，logback 的内部运行流程如下所示</p>
<ol>
<li><p>获得过滤器链条</p>
</li>
<li><p>检查日志级别以决定是否继续打印</p>
</li>
<li><p>创建一个 LoggingEvent 对象</p>
</li>
<li><p>调用 Appenders</p>
</li>
<li><p>进行日志信息格式化</p>
</li>
<li><p>发送 LoggingEvent 到对应的目的地</p>
</li>
</ol>
<h3 id="有关性能问题"><a href="#有关性能问题" class="headerlink" title="有关性能问题"></a>有关性能问题</h3><p>关于日志系统，人们讨论得最多的是性能问题，即使是小型的应用程序，也有可能输出大量的日志。打印日志中的不当处理，会引发各种性能问题，例如太多的日志记录请求可能使磁盘 IO 成为性能瓶颈，从而影响到应用程序的正常运行。在合适的时候记录日志、以更好的方式发起日志请求、以及合理设置日志级别方面，都有可能造成性能问题。<br>关于性能问题，以下几个方面需要了解</p>
<ul>
<li><p>建议使用占位符的方式参数化记录日志</p>
</li>
<li><p>logback 内部机制保证 logger 在记录日志时，不必每一次都去遍历它的父辈以获得关于日志级别、Appender 的信息</p>
</li>
<li><p>在 logback 中，将日志信息格式化，以及输出到目的地，是最损耗性能的操作</p>
</li>
</ul>
<h2 id="logback-配置"><a href="#logback-配置" class="headerlink" title="logback 配置"></a>logback 配置</h2><h3 id="配置须知"><a href="#配置须知" class="headerlink" title="配置须知"></a>配置须知</h3><h4 id="配置方式"><a href="#配置方式" class="headerlink" title="配置方式"></a>配置方式</h4><p>logback 提供的配置方式有以下几种：</p>
<ul>
<li><p>编程式配置</p>
</li>
<li><p>xml 格式</p>
</li>
<li><p>groovy 格式</p>
</li>
</ul>
<p>logback 在启动时，根据以下步骤寻找配置文件：</p>
<ol>
<li><p>在 classpath 中寻找 logback-test.xml文件</p>
</li>
<li><p>如果找不到 logback-test.xml，则在 classpath 中寻找 logback.groovy 文件</p>
</li>
<li><p>如果找不到 logback.groovy，则在 classpath 中寻找 logback.xml文件</p>
</li>
<li><p>如果上述的文件都找不到，则 logback 会使用 JDK 的 SPI 机制查找 META-INF/services/ch.qos.logback.classic.spi.Configurator 中的 logback 配置实现类，这个实现类必须实现 Configuration 接口，使用它的实现来进行配置</p>
</li>
<li><p>如果上述操作都不成功，logback 就会使用它自带的 BasicConfigurator 来配置，并将日志输出到 console</p>
</li>
</ol>
<p>logback-test.xml 一般用来在测试代码中打日志，如果是 maven 项目，一般把 logback-test.xml 放在 src/test/resources 目录下。maven 打包的时候也不会把这个文件打进 jar 包里。<br>logback 启动的时候解析配置文件大概需要 100 毫秒的时间，如果希望更快启动，可以采用 SPI 的方式。</p>
<h4 id="默认的配置"><a href="#默认的配置" class="headerlink" title="默认的配置"></a>默认的配置</h4><p>前面有提到默认的配置，由 BasicConfiguator 类配置而成，这个类的配置可以用如下的配置文件来表示：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">"STDOUT"</span> <span class="attr">class</span>=<span class="string">"ch.qos.logback.core.ConsoleAppender"</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- encoders are assigned the type</span></span><br><span class="line"><span class="comment">         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">encoder</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">pattern</span>&gt;</span>%d&#123;HH:mm:ss.SSS&#125; [%thread] %-5level %logger&#123;36&#125; - %msg%n<span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">encoder</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">root</span> <span class="attr">level</span>=<span class="string">"debug"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">"STDOUT"</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h4 id="启动时打印状态信息"><a href="#启动时打印状态信息" class="headerlink" title="启动时打印状态信息"></a>启动时打印状态信息</h4><p>如果 logback 在启动时，解析配置文件时，出现了需要警告的信息或者错误信息，那 logback 会自动先打印出自身的状态信息。</p>
<p>如果希望正常情况下也打印出状态信息，则可以使用之前提到的方式，在代码里显式地调用使其输出：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">  <span class="comment">// assume SLF4J is bound to logback in the current environment</span></span><br><span class="line">  LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();</span><br><span class="line">  <span class="comment">// print logback's internal status</span></span><br><span class="line">  StatusPrinter.print(lc);</span><br><span class="line">  ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>也可以在配置文件中，指定 <code>configuration</code> 的 debug 属性为 true<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span> <span class="attr">debug</span>=<span class="string">"true"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">"STDOUT"</span> <span class="attr">class</span>=<span class="string">"ch.qos.logback.core.ConsoleAppender"</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder </span></span><br><span class="line"><span class="comment">            by default --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">encoder</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">pattern</span>&gt;</span>%d&#123;HH:mm:ss.SSS&#125; [%thread] %-5level %logger&#123;36&#125; - %msg%n</span><br><span class="line">            <span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">encoder</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">root</span> <span class="attr">level</span>=<span class="string">"debug"</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">"STDOUT"</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>还可以指定一个 Listener：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">statusListener</span> <span class="attr">class</span>=<span class="string">"ch.qos.logback.core.status.OnConsoleStatusListener"</span> /&gt;</span>  </span><br><span class="line">  ... the rest of the configuration file  </span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h4 id="重置默认的配置文件位置"><a href="#重置默认的配置文件位置" class="headerlink" title="重置默认的配置文件位置"></a>重置默认的配置文件位置</h4><p>设置 logback.configurationFile 系统变量，可以通过 -D 参数设置，所指定的文件名必须以 .xml 或者 .groovy 作为文件后缀，否则 logback 会忽略这些文件。</p>
<h4 id="配置文件自动热加载"><a href="#配置文件自动热加载" class="headerlink" title="配置文件自动热加载"></a>配置文件自动热加载</h4><p>要使配置文件自动重载，需要把 scan 属性设置为 true，默认情况下每分钟才会扫描一次，可以指定扫描间隔：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span> <span class="attr">scan</span>=<span class="string">"true"</span> <span class="attr">scanPeriod</span>=<span class="string">"30 seconds"</span> &gt;</span> </span><br><span class="line">  ...</span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>注意扫描间隔要加上单位，可用的单位是 <code>milliseconds，seconds，minutes 和 hours</code>。如果只指定了数字，但没有指定单位，这默认单位为 milliseconds。</p>
<p>在 logback 内部，当设置 scan 属性为 true 后，一个叫做 <code>ReconfigureOnChangeFilter</code>的过滤器就会被牵扯进来，它负责判断是否到了该扫描的时候，以及是否该重新加载配置。Logger 的任何一个打印日志的方法被调用时，都会触发这个过滤器，所以关于这个过滤器的自身的性能问题，变得十分重要。logback 目前采用这样一种机制，当 logger 的调用次数到达一定次数后，才真正让过滤器去做它要做的事情，这个次数默认是 16，而 logback 会在运行时根据调用的频繁度来动态调整这个数目。</p>
<h4 id="输出异常栈时也打印出-jar-包的信息"><a href="#输出异常栈时也打印出-jar-包的信息" class="headerlink" title="输出异常栈时也打印出 jar 包的信息"></a>输出异常栈时也打印出 jar 包的信息</h4><p>这个属性默认是关闭，可通过以下方式开启：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span> <span class="attr">packagingData</span>=<span class="string">"true"</span>&gt;</span></span><br><span class="line">  ...</span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>也可以通过 <code>LoggerContext</code> 的 <code>setPackagingDataEnabled(boolean)</code>方法来开启</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();</span><br><span class="line"> lc.setPackagingDataEnabled(true);</span><br></pre></td></tr></table></figure>
<h4 id="直接调用-JoranConfigurator"><a href="#直接调用-JoranConfigurator" class="headerlink" title="直接调用 JoranConfigurator"></a>直接调用 <code>JoranConfigurator</code></h4><p><code>Joran</code> 是 logback 使用的一个配置加载库，如果想要重新实现 logback 的配置机制，可以直接调用这个类 JoranConfigurator 来实现：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> chapters.configuration;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.slf4j.Logger;</span><br><span class="line"><span class="keyword">import</span> org.slf4j.LoggerFactory;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> ch.qos.logback.classic.LoggerContext;</span><br><span class="line"><span class="keyword">import</span> ch.qos.logback.classic.joran.JoranConfigurator;</span><br><span class="line"><span class="keyword">import</span> ch.qos.logback.core.joran.spi.JoranException;</span><br><span class="line"><span class="keyword">import</span> ch.qos.logback.core.util.StatusPrinter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyApp3</span> </span>&#123;</span><br><span class="line">  <span class="keyword">final</span> <span class="keyword">static</span> Logger logger = LoggerFactory.getLogger(MyApp3.class);</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">    <span class="comment">// assume SLF4J is bound to logback in the current environment</span></span><br><span class="line">    LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      JoranConfigurator configurator = <span class="keyword">new</span> JoranConfigurator();</span><br><span class="line">      configurator.setContext(context);</span><br><span class="line">      <span class="comment">// Call context.reset() to clear any previous configuration, e.g. default </span></span><br><span class="line">      <span class="comment">// configuration. For multi-step configuration, omit calling context.reset().</span></span><br><span class="line">      context.reset(); </span><br><span class="line">      configurator.doConfigure(args[<span class="number">0</span>]);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (JoranException je) &#123;</span><br><span class="line">      <span class="comment">// StatusPrinter will handle this</span></span><br><span class="line">    &#125;</span><br><span class="line">    StatusPrinter.printInCaseOfErrorsOrWarnings(context);</span><br><span class="line"></span><br><span class="line">    logger.info(<span class="string">"Entering application."</span>);</span><br><span class="line"></span><br><span class="line">    Foo foo = <span class="keyword">new</span> Foo();</span><br><span class="line">    foo.doIt();</span><br><span class="line">    logger.info(<span class="string">"Exiting application."</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h3 id="配置文件格式"><a href="#配置文件格式" class="headerlink" title="配置文件格式"></a>配置文件格式</h3><h4 id="配置文件的基本结构"><a href="#配置文件的基本结构" class="headerlink" title="配置文件的基本结构"></a>配置文件的基本结构</h4><p><img src="_v_images/_1540969013_11481.png" alt></p>
<p>根节点是 configuration，可包含0个或多个 appender，0个或多个 logger，最多一个 root。</p>
<h4 id="配置-logger-节点"><a href="#配置-logger-节点" class="headerlink" title="配置 logger 节点"></a>配置 logger 节点</h4><p>在配置文件中，logger 的配置在<logger> 标签中配置，<logger> 标签只有一个属性是一定要的，那就是 name，除了 name 属性，还有 level 属性，additivity 属性可以配置，不过它们是可选的。<br>level 的取值可以是 <code>TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF, INHERITED, NULL</code>， 其中 <code>INHERITED</code>和<code>NULL</code>的作用是一样的，并不是不打印任何日志，而是强制这个 logger 必须从其父辈继承一个日志级别。<br>additivity 的取值是一个布尔值，true 或者 false。</logger></logger></p>
<p><logger> 标签下只有一种元素，那就是 <appender-ref>，可以有0个或多个，意味着绑定到这个 logger 上的 Appender。</appender-ref></logger></p>
<h4 id="配置-root-节点"><a href="#配置-root-节点" class="headerlink" title="配置 root 节点"></a>配置 root 节点</h4><p><root> 标签和 <logger> 标签的配置类似，只不过 <root> 标签只允许一个属性，那就是 level 属性，并且它的取值范围只能取 <code>TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF。</code></root></logger></root></p>
<p><root> 标签下允许有0个或者多个 <appender-ref>。</appender-ref></root></p>
<h4 id="配置-appender-节点"><a href="#配置-appender-节点" class="headerlink" title="配置 appender 节点"></a>配置 appender 节点</h4><p><appender> 标签有两个必须填的属性，分别是 name 和 class，class 用来指定具体的实现类。<appender> 标签下可以包含至多一个 <layout>，0个或多个 <encoder>，0个或多个 <filter>，除了这些标签外，<appender> 下可以包含一些类似于 JavaBean 的配置标签。</appender></filter></encoder></layout></appender></appender></p>
<p><layout> 包含了一个必须填写的属性 class，用来指定具体的实现类，不过，如果该实现类的类型是 <code>PatternLayout</code> 时，那么可以不用填写。<layout> 也和 <appender> 一样，可以包含类似于 JavaBean 的配置标签。</appender></layout></layout></p>
<p><encoder> 标签包含一个必须填写的属性 class，用来指定具体的实现类，如果该类的类型是 <code>PatternLayoutEncode</code>r ，那么 class 属性可以不填。<br>如果想要往一个 logger 上绑定 appender，则使用以下方式：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">logger</span> <span class="attr">name</span>=<span class="string">"HELLO"</span> <span class="attr">level</span>=<span class="string">"debug"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">"FILE"</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">"STDOUT"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">logger</span>&gt;</span></span><br></pre></td></tr></table></figure></encoder></p>
<h4 id="设置-Context-Name"><a href="#设置-Context-Name" class="headerlink" title="设置 Context Name"></a>设置 Context Name</h4><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">contextName</span>&gt;</span>myAppName<span class="tag">&lt;/<span class="name">contextName</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">"STDOUT"</span> <span class="attr">class</span>=<span class="string">"ch.qos.logback.core.ConsoleAppender"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">encoder</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">pattern</span>&gt;</span>%d %contextName [%t] %level %logger&#123;36&#125; - %msg%n<span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">encoder</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">root</span> <span class="attr">level</span>=<span class="string">"debug"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">"STDOUT"</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h4 id="变量替换"><a href="#变量替换" class="headerlink" title="变量替换"></a>变量替换</h4><p>在 logback 中，支持以 ${varName} 来引用变量</p>
<h5 id="定义变量"><a href="#定义变量" class="headerlink" title="定义变量"></a>定义变量</h5><p>可以直接在 logback.xml 中定义变量<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"USER_HOME"</span> <span class="attr">value</span>=<span class="string">"/home/sebastien"</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">"FILE"</span> <span class="attr">class</span>=<span class="string">"ch.qos.logback.core.FileAppender"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">file</span>&gt;</span>$&#123;USER_HOME&#125;/myApp.log<span class="tag">&lt;/<span class="name">file</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">encoder</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">pattern</span>&gt;</span>%msg%n<span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">encoder</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">root</span> <span class="attr">level</span>=<span class="string">"debug"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">"FILE"</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>也可以通过大D参数来定义</p>
<p><code>java -DUSER_HOME=&quot;/home/sebastien&quot; MyApp2</code><br>也可以通过外部文件来定义<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">property</span> <span class="attr">file</span>=<span class="string">"src/main/java/chapters/configuration/variables1.properties"</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">"FILE"</span> <span class="attr">class</span>=<span class="string">"ch.qos.logback.core.FileAppender"</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">file</span>&gt;</span>$&#123;USER_HOME&#125;/myApp.log<span class="tag">&lt;/<span class="name">file</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">encoder</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">pattern</span>&gt;</span>%msg%n<span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;/<span class="name">encoder</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br><span class="line"></span><br><span class="line">   <span class="tag">&lt;<span class="name">root</span> <span class="attr">level</span>=<span class="string">"debug"</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">"FILE"</span> /&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>外部文件也支持 classpath 中的文件<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">property</span> <span class="attr">resource</span>=<span class="string">"resource1.properties"</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">"FILE"</span> <span class="attr">class</span>=<span class="string">"ch.qos.logback.core.FileAppender"</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">file</span>&gt;</span>$&#123;USER_HOME&#125;/myApp.log<span class="tag">&lt;/<span class="name">file</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">encoder</span>&gt;</span></span><br><span class="line">       <span class="tag">&lt;<span class="name">pattern</span>&gt;</span>%msg%n<span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;/<span class="name">encoder</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br><span class="line"></span><br><span class="line">   <span class="tag">&lt;<span class="name">root</span> <span class="attr">level</span>=<span class="string">"debug"</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">"FILE"</span> /&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>外部文件的格式是 key-value 型。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">USER_HOME=/home/sebastien</span><br></pre></td></tr></table></figure></p>
<h5 id="变量的作用域"><a href="#变量的作用域" class="headerlink" title="变量的作用域"></a>变量的作用域</h5><p>变量有三个作用域</p>
<ul>
<li>local</li>
<li>context</li>
<li>system</li>
</ul>
<p>local 作用域在配置文件内有效，context 作用域的有效范围延伸至 logger context，system 作用域的范围最广，整个 JVM 内都有效。</p>
<p>logback 在替换变量时，首先搜索 local 变量，然后搜索 context，然后搜索 system。</p>
<p>如何为变量指定 scope ?<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">property</span> <span class="attr">scope</span>=<span class="string">"context"</span> <span class="attr">name</span>=<span class="string">"nodeId"</span> <span class="attr">value</span>=<span class="string">"firstNode"</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">"FILE"</span> <span class="attr">class</span>=<span class="string">"ch.qos.logback.core.FileAppender"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">file</span>&gt;</span>/opt/$&#123;nodeId&#125;/myApp.log<span class="tag">&lt;/<span class="name">file</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">encoder</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">pattern</span>&gt;</span>%msg%n<span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">encoder</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">root</span> <span class="attr">level</span>=<span class="string">"debug"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">"FILE"</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h5 id="变量的默认值"><a href="#变量的默认值" class="headerlink" title="变量的默认值"></a>变量的默认值</h5><p>在引用一个变量时，如果该变量未定义，那么可以为其指定默认值，做法是：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$&#123;aName:-golden&#125;</span><br></pre></td></tr></table></figure></p>
<h5 id="运行时定义变量"><a href="#运行时定义变量" class="headerlink" title="运行时定义变量"></a>运行时定义变量</h5><p>需要使用 <define> 标签，指定接口 PropertyDfiner 对应的实现类。如下所示：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">define</span> <span class="attr">name</span>=<span class="string">"rootLevel"</span> <span class="attr">class</span>=<span class="string">"a.class.implementing.PropertyDefiner"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">shape</span>&gt;</span>round<span class="tag">&lt;/<span class="name">shape</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">color</span>&gt;</span>brown<span class="tag">&lt;/<span class="name">color</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">size</span>&gt;</span>24<span class="tag">&lt;/<span class="name">size</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">define</span>&gt;</span></span><br><span class="line"> </span><br><span class="line">  <span class="tag">&lt;<span class="name">root</span> <span class="attr">level</span>=<span class="string">"$&#123;rootLevel&#125;"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure></define></p>
<h5 id="条件化处理配置文件"><a href="#条件化处理配置文件" class="headerlink" title="条件化处理配置文件"></a>条件化处理配置文件</h5><p>logback 允许在配置文件中定义条件语句，以决定配置的不同行为，具体语法格式如下：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">&lt;!-- if-then form --&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">if</span> <span class="attr">condition</span>=<span class="string">"some conditional expression"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">then</span>&gt;</span></span><br><span class="line">    ...</span><br><span class="line">  <span class="tag">&lt;/<span class="name">then</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">if</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!-- if-then-else form --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">if</span> <span class="attr">condition</span>=<span class="string">"some conditional expression"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">then</span>&gt;</span></span><br><span class="line">    ...</span><br><span class="line">  <span class="tag">&lt;/<span class="name">then</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">else</span>&gt;</span></span><br><span class="line">    ...</span><br><span class="line">  <span class="tag">&lt;/<span class="name">else</span>&gt;</span>    </span><br><span class="line"><span class="tag">&lt;/<span class="name">if</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>示例：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span> <span class="attr">debug</span>=<span class="string">"true"</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">if</span> <span class="attr">condition</span>=<span class="string">'property("HOSTNAME").contains("torino")'</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">then</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">"CON"</span> <span class="attr">class</span>=<span class="string">"ch.qos.logback.core.ConsoleAppender"</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">encoder</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;<span class="name">pattern</span>&gt;</span>%d %-5level %logger&#123;35&#125; - %msg %n<span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">encoder</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">root</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">"CON"</span> /&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">then</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">if</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">"FILE"</span> <span class="attr">class</span>=<span class="string">"ch.qos.logback.core.FileAppender"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">file</span>&gt;</span>$&#123;randomOutputDir&#125;/conditional.log<span class="tag">&lt;/<span class="name">file</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">encoder</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">pattern</span>&gt;</span>%d %-5level %logger&#123;35&#125; - %msg %n<span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">encoder</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">root</span> <span class="attr">level</span>=<span class="string">"ERROR"</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">"FILE"</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h5 id="从JNDI-获取变量"><a href="#从JNDI-获取变量" class="headerlink" title="从JNDI 获取变量"></a>从JNDI 获取变量</h5><p>使用 <insertfromjndi> 可以从 JNDI 加载变量，如下所示：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">insertFromJNDI</span> <span class="attr">env-entry-name</span>=<span class="string">"java:comp/env/appName"</span> <span class="attr">as</span>=<span class="string">"appName"</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">contextName</span>&gt;</span>$&#123;appName&#125;<span class="tag">&lt;/<span class="name">contextName</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">"CONSOLE"</span> <span class="attr">class</span>=<span class="string">"ch.qos.logback.core.ConsoleAppender"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">encoder</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">pattern</span>&gt;</span>%d $&#123;CONTEXT_NAME&#125; %level %msg %logger&#123;50&#125;%n<span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">encoder</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">root</span> <span class="attr">level</span>=<span class="string">"DEBUG"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">"CONSOLE"</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure></insertfromjndi></p>
<h5 id="文件包含"><a href="#文件包含" class="headerlink" title="文件包含"></a>文件包含</h5><p>可以使用 ≶include&gt; 标签在一个配置文件中包含另外一个配置文件，如下图所示：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">include</span> <span class="attr">file</span>=<span class="string">"src/main/java/chapters/configuration/includedConfig.xml"</span>/&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="name">root</span> <span class="attr">level</span>=<span class="string">"DEBUG"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">"includedConsole"</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>被包含的文件必须有以下格式：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">included</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">"includedConsole"</span> <span class="attr">class</span>=<span class="string">"ch.qos.logback.core.ConsoleAppender"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">encoder</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">pattern</span>&gt;</span>"%d - %m%n"<span class="tag">&lt;/<span class="name">pattern</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">encoder</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">included</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>支持从多种源头包含<br>从文件中包含<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">include</span> <span class="attr">file</span>=<span class="string">"src/main/java/chapters/configuration/includedConfig.xml"</span>/&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>从 classpath 中包含<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;include resource=&quot;includedConfig.xml&quot;/&gt;</span><br></pre></td></tr></table></figure></p>
<p>从 URL 中包含<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;include url=&quot;http://some.host.com/includedConfig.xml&quot;/&gt;</span><br></pre></td></tr></table></figure></p>
<p>如果包含不成功，那么 logback 会打印出一条警告信息，如果不希望 logback 抱怨，只需这样做：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;include optional=&quot;true&quot; ..../&gt;</span><br></pre></td></tr></table></figure></p>
<h4 id="添加一个-Context-Listener"><a href="#添加一个-Context-Listener" class="headerlink" title="添加一个 Context Listener"></a>添加一个 Context Listener</h4><p><code>LoggerContextListener</code> 接口的实例能监听 logger context 上发生的事件，比如说日志级别的变化，添加的方式如下所示：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span> <span class="attr">debug</span>=<span class="string">"true"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">contextListener</span> <span class="attr">class</span>=<span class="string">"ch.qos.logback.classic.jul.LevelChangePropagator"</span>/&gt;</span></span><br><span class="line">  .... </span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure></p>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/java/" rel="tag"># java</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2018/10/31/java日志框架/logback的配置信息/" rel="next" title="logback配置详解">
                <i class="fa fa-chevron-left"></i> logback配置详解
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2018/11/01/linux/linux下的各种解压与压缩/" rel="prev" title="linux下的各种解压与压缩">
                linux下的各种解压与压缩 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">xiezc</p>
              <p class="site-description motion-element" itemprop="description">主要一些技术文章, 有些文章是转载的</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/">
              
                  <span class="site-state-item-count">72</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                
                  <span class="site-state-item-count">1</span>
                  <span class="site-state-item-name">分类</span>
                
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                
                  <span class="site-state-item-count">20</span>
                  <span class="site-state-item-name">标签</span>
                
              </div>
            

          </nav>

          

          

          
          

          
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#logback详解"><span class="nav-number">1.</span> <span class="nav-text">logback详解</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#引用自-https-segmentfault-com-a-1190000008315137-articleHeader28"><span class="nav-number">1.1.</span> <span class="nav-text">引用自: https://segmentfault.com/a/1190000008315137#articleHeader28</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#概览"><span class="nav-number">1.2.</span> <span class="nav-text">概览</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Logback-与-Log4J"><span class="nav-number">1.3.</span> <span class="nav-text">Logback 与 Log4J</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#快速上手"><span class="nav-number">1.4.</span> <span class="nav-text">快速上手</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#第一个简单的例子"><span class="nav-number">1.4.1.</span> <span class="nav-text">第一个简单的例子</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#让-Logback-打印出一些它自身的内部消息"><span class="nav-number">1.4.2.</span> <span class="nav-text">让 Logback 打印出一些它自身的内部消息</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Logger，Appenders-与-Layouts"><span class="nav-number">1.5.</span> <span class="nav-text">Logger，Appenders 与 Layouts</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#分层命名规则"><span class="nav-number">1.5.1.</span> <span class="nav-text">分层命名规则</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#日志打印级别"><span class="nav-number">1.5.2.</span> <span class="nav-text">日志打印级别</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#获取-logger"><span class="nav-number">1.5.3.</span> <span class="nav-text">获取 logger</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Appender-和-Layout"><span class="nav-number">1.5.4.</span> <span class="nav-text">Appender 和 Layout</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#参数化打印日志"><span class="nav-number">1.5.5.</span> <span class="nav-text">参数化打印日志</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#logback-内部运行流程"><span class="nav-number">1.5.6.</span> <span class="nav-text">logback 内部运行流程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#有关性能问题"><span class="nav-number">1.5.7.</span> <span class="nav-text">有关性能问题</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#logback-配置"><span class="nav-number">1.6.</span> <span class="nav-text">logback 配置</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#配置须知"><span class="nav-number">1.6.1.</span> <span class="nav-text">配置须知</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#配置方式"><span class="nav-number">1.6.1.1.</span> <span class="nav-text">配置方式</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#默认的配置"><span class="nav-number">1.6.1.2.</span> <span class="nav-text">默认的配置</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#启动时打印状态信息"><span class="nav-number">1.6.1.3.</span> <span class="nav-text">启动时打印状态信息</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#重置默认的配置文件位置"><span class="nav-number">1.6.1.4.</span> <span class="nav-text">重置默认的配置文件位置</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#配置文件自动热加载"><span class="nav-number">1.6.1.5.</span> <span class="nav-text">配置文件自动热加载</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#输出异常栈时也打印出-jar-包的信息"><span class="nav-number">1.6.1.6.</span> <span class="nav-text">输出异常栈时也打印出 jar 包的信息</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#直接调用-JoranConfigurator"><span class="nav-number">1.6.1.7.</span> <span class="nav-text">直接调用 JoranConfigurator</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#配置文件格式"><span class="nav-number">1.6.2.</span> <span class="nav-text">配置文件格式</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#配置文件的基本结构"><span class="nav-number">1.6.2.1.</span> <span class="nav-text">配置文件的基本结构</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#配置-logger-节点"><span class="nav-number">1.6.2.2.</span> <span class="nav-text">配置 logger 节点</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#配置-root-节点"><span class="nav-number">1.6.2.3.</span> <span class="nav-text">配置 root 节点</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#配置-appender-节点"><span class="nav-number">1.6.2.4.</span> <span class="nav-text">配置 appender 节点</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#设置-Context-Name"><span class="nav-number">1.6.2.5.</span> <span class="nav-text">设置 Context Name</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#变量替换"><span class="nav-number">1.6.2.6.</span> <span class="nav-text">变量替换</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#定义变量"><span class="nav-number">1.6.2.6.1.</span> <span class="nav-text">定义变量</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#变量的作用域"><span class="nav-number">1.6.2.6.2.</span> <span class="nav-text">变量的作用域</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#变量的默认值"><span class="nav-number">1.6.2.6.3.</span> <span class="nav-text">变量的默认值</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#运行时定义变量"><span class="nav-number">1.6.2.6.4.</span> <span class="nav-text">运行时定义变量</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#条件化处理配置文件"><span class="nav-number">1.6.2.6.5.</span> <span class="nav-text">条件化处理配置文件</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#从JNDI-获取变量"><span class="nav-number">1.6.2.6.6.</span> <span class="nav-text">从JNDI 获取变量</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#文件包含"><span class="nav-number">1.6.2.6.7.</span> <span class="nav-text">文件包含</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#添加一个-Context-Listener"><span class="nav-number">1.6.2.7.</span> <span class="nav-text">添加一个 Context Listener</span></a></li></ol></li></ol></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2019</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">xiezc</span>

  
</div>


  <div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动</div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Gemini</a> v5.1.4</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.4"></script>



  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  












  





  

  
  <script src="https://cdn1.lncld.net/static/js/av-core-mini-0.6.4.js"></script>
  <script>AV.initialize("eRAHvO0xVYwckgdXIVpfugRG-gzGzoHsz", "57lKp708hde92YeG1xX9MQj1");</script>
  <script>
    function showTime(Counter) {
      var query = new AV.Query(Counter);
      var entries = [];
      var $visitors = $(".leancloud_visitors");

      $visitors.each(function () {
        entries.push( $(this).attr("id").trim() );
      });

      query.containedIn('url', entries);
      query.find()
        .done(function (results) {
          var COUNT_CONTAINER_REF = '.leancloud-visitors-count';

          if (results.length === 0) {
            $visitors.find(COUNT_CONTAINER_REF).text(0);
            return;
          }

          for (var i = 0; i < results.length; i++) {
            var item = results[i];
            var url = item.get('url');
            var time = item.get('time');
            var element = document.getElementById(url);

            $(element).find(COUNT_CONTAINER_REF).text(time);
          }
          for(var i = 0; i < entries.length; i++) {
            var url = entries[i];
            var element = document.getElementById(url);
            var countSpan = $(element).find(COUNT_CONTAINER_REF);
            if( countSpan.text() == '') {
              countSpan.text(0);
            }
          }
        })
        .fail(function (object, error) {
          console.log("Error: " + error.code + " " + error.message);
        });
    }

    function addCount(Counter) {
      var $visitors = $(".leancloud_visitors");
      var url = $visitors.attr('id').trim();
      var title = $visitors.attr('data-flag-title').trim();
      var query = new AV.Query(Counter);

      query.equalTo("url", url);
      query.find({
        success: function(results) {
          if (results.length > 0) {
            var counter = results[0];
            counter.fetchWhenSave(true);
            counter.increment("time");
            counter.save(null, {
              success: function(counter) {
                var $element = $(document.getElementById(url));
                $element.find('.leancloud-visitors-count').text(counter.get('time'));
              },
              error: function(counter, error) {
                console.log('Failed to save Visitor num, with error message: ' + error.message);
              }
            });
          } else {
            var newcounter = new Counter();
            /* Set ACL */
            var acl = new AV.ACL();
            acl.setPublicReadAccess(true);
            acl.setPublicWriteAccess(true);
            newcounter.setACL(acl);
            /* End Set ACL */
            newcounter.set("title", title);
            newcounter.set("url", url);
            newcounter.set("time", 1);
            newcounter.save(null, {
              success: function(newcounter) {
                var $element = $(document.getElementById(url));
                $element.find('.leancloud-visitors-count').text(newcounter.get('time'));
              },
              error: function(newcounter, error) {
                console.log('Failed to create');
              }
            });
          }
        },
        error: function(error) {
          console.log('Error:' + error.code + " " + error.message);
        }
      });
    }

    $(function() {
      var Counter = AV.Object.extend("Counter");
      if ($('.leancloud_visitors').length == 1) {
        addCount(Counter);
      } else if ($('.post-title-link').length > 1) {
        showTime(Counter);
      }
    });
  </script>



  

  
<script>
(function(){
    var bp = document.createElement('script');
    var curProtocol = window.location.protocol.split(':')[0];
    if (curProtocol === 'https') {
        bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';        
    }
    else {
        bp.src = 'http://push.zhanzhang.baidu.com/push.js';
    }
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(bp, s);
})();
</script>


  
  

  

  

  

</body>
</html>
